package com.lvmama.rhino.web.comment.category.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lvmama.rhino.pojo.comment.Enum.CommentDaysEnum;
import com.lvmama.rhino.pojo.comment.Enum.EnumForCategory;
import com.lvmama.rhino.pojo.comment.Enum.EnumForComment;
import com.lvmama.rhino.pojo.comment.entity.vo.*;
import com.lvmama.rhino.pojo.comment.request.*;
import com.lvmama.rhino.service.comment.CategoryRankService;
import com.lvmama.rhino.service.impl.comment.RedisServiceImpl;
import com.lvmama.rhino.utils.Constants;
import com.lvmama.rhino.utils.DateUtil;
import com.lvmama.rhino.utils.StringTools;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping("category")
public class CategoryController {

    @Autowired
    private CategoryRankService categoryRankService;

    private Logger log = Logger.getLogger(CategoryController.class);

    @RequestMapping("favorcomp")
    public String favorcompView(Model model, FavorcompRequest request) {
        model.addAttribute("favorcompReq", request);
        return "application/category/favorcomp";
    }

    @Autowired
    private RedisServiceImpl redisService;

    /**
     * 2. 品类满意度趋势
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "getOneCommentOrient", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getOneCommentOrient(CategoryCommentRateRequest request) {
        Map<String, Object> resultMap = new HashMap<>();
        log.info("品类满意度趋势getOneCommentOrient");
        try {
            Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
            request.setBeginDate(map.get("beginDate"));
            request.setEndDate(map.get("endDate"));
            if (StringUtils.isBlank(request.getCategoryName())) return resultMap;
            request.setCategoryId(EnumForCategory.getCategoryValueByShowName(request.getCategoryName()));
            List<CategoryCommentOrientVO> orientList = categoryRankService.getOneCommentOrient(request);
            log.info("品类满意度趋势getOneCommentOrient查询到:" + orientList.size() + "条结果");
            JSONArray commentOrientArray = transToOrientArray(orientList, request.getBeginDate(), request.getEndDate());
            resultMap.put("commentOrientChart", commentOrientArray);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("品类满意度趋势getOneCommentOrient查询出错:" + e.getMessage(), e);
        }
        return resultMap;
    }

    private JSONArray transToOrientArray(List<CategoryCommentOrientVO> orientList,
                                         Date beginDate, Date endDate) {

        List<CategoryCommentOrientVO> result = new ArrayList<>();
        // 根据选择的日期 为空的补0
        List<String> dates = DateUtil.getBetweenDates(beginDate, endDate, "yyyy-MM-dd");
        if (!CollectionUtils.isEmpty(orientList) && !CollectionUtils.isEmpty(dates)) {
            for (int i = 0; i < dates.size(); i++) {
                String curday = dates.get(i);
                for (int j = 0; j < orientList.size(); j++) {
                    CategoryCommentOrientVO vo = orientList.get(j);
                    if (curday.equals(vo.getSubDay())) {
                        result.add(vo);
                        break;
                    }
                }
                if (result.size() < i + 1) {
                    CategoryCommentOrientVO orientVO = new CategoryCommentOrientVO();
                    orientVO.setFavorRate(0f);
                    orientVO.setMiddleRate(0f);
                    orientVO.setWorstRate(0f);
                    orientVO.setSubDay(curday);
                    result.add(orientVO);
                }
            }
        }

        JSONArray commentOrientArray = new JSONArray();
        for (int i = 0; i < result.size(); i++) {
            CategoryCommentOrientVO vo = result.get(i);
            //构造方法的字符格式这里如果小数不足2位,会以0补足.
            float favorRate = new BigDecimal(vo.getFavorRate()).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
            float middleRate = new BigDecimal(vo.getMiddleRate()).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
            float worstRate = new BigDecimal(vo.getWorstRate()).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();

            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("month", vo.getSubDay());
            jsonObject1.put("type", "好评");
            jsonObject1.put("rate", favorRate);
            commentOrientArray.add(jsonObject1);

            JSONObject jsonObject2 = new JSONObject();
            jsonObject2.put("month", vo.getSubDay());
            jsonObject2.put("type", "中评");
            jsonObject2.put("rate", middleRate);
            commentOrientArray.add(jsonObject2);

            JSONObject jsonObject3 = new JSONObject();
            jsonObject3.put("month", vo.getSubDay());
            jsonObject3.put("type", "差评");
            jsonObject3.put("rate", worstRate);
            commentOrientArray.add(jsonObject3);
        }
        return commentOrientArray;
    }

    /**
     * 1. 品类满意度分析
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "getAllCategoryRankChart", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getCommentRate(CategoryCommentRateRequest request) {
        Map<String, Object> resultMap = new HashMap<>();
        List<CategoryCommentCountVO> rankChartVoList = new ArrayList<>();
        String rankChartVoListStr;
        log.info("品类满意度分析getAllCategoryRankChart");
        try {
            Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
            request.setBeginDate(map.get("beginDate"));
            request.setEndDate(map.get("endDate"));


            String key = redisService.getKey("getAllCategoryRankChart");
            if (isCategoryRankQueryRedis(request.getBeginDate(), request.getEndDate(), null)) {
                log.info("category getAllCategoryRankChart redis query start");
                rankChartVoListStr = redisService.getObjectValue(key);
                log.info("category getAllCategoryRankChart redis query end");
                if (StringUtils.isNotBlank(rankChartVoListStr)) {
                    rankChartVoList = new Gson().fromJson(rankChartVoListStr, new TypeToken<List<CategoryCommentCountVO>>() {}.getType());
                } else {
                    rankChartVoList = queryAllCategoryRankChart(request);
                    redisService.setValueExpire(key, rankChartVoList, Constants.TIMEOUT);
                }
            } else {
                rankChartVoList = queryAllCategoryRankChart(request);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("category getAllCategoryRankChart query error:" + e.getMessage(), e);
            try {
                rankChartVoList = queryAllCategoryRankChart(request);
            } catch (Exception e1) {
                e1.printStackTrace();
                log.error("category getAllCategoryRankChart mysql requery error:" + e1.getMessage(), e1);
            }
        }

        try {
            log.info("品类满意度分析getAllCategoryRankChart查询到" + rankChartVoList.size() + "条结果");
            JSONArray commentRateArray = new JSONArray();
            transTorankArray(commentRateArray, rankChartVoList, resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("品类满意度分析getAllCategoryRankChart数据解析出错:" + e.getMessage(), e);
        }
        return resultMap;
    }

    /**
     * 品类满意度分析-mysql查询
     * @param request
     * @return
     * @throws
     */
    private List<CategoryCommentCountVO> queryAllCategoryRankChart(CategoryCommentRateRequest request) throws Exception {
        log.info("category getAllCategoryRankChart queryAllCategoryRankChart mysql query start");
        List<CategoryCommentCountVO> countVOList = categoryRankService.getCategoryCommentCount(request);
        log.info("category getAllCategoryRankChart queryAllCategoryRankChart mysql end");
        return countVOList;
    }

    /**
     * 3. 品类满意度占比
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "getOneCategoryRankChart", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getOneCategoryRankChart(CategoryCommentRateRequest request) {
        Map<String, Object> resultMap = new HashMap<>();
        log.info("品类满意度占比getOneCategoryRankChart");
        try {
            Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
            request.setBeginDate(map.get("beginDate"));
            request.setEndDate(map.get("endDate"));
            if (StringUtils.isBlank(request.getCategoryName())) return resultMap;
            request.setCategoryId(EnumForCategory.getCategoryValueByShowName(request.getCategoryName()));
            JSONArray categoryRateArray = new JSONArray();
            CategoryCommentRateVO commentRateVO = categoryRankService.getOneCommentRate(request);
            log.info("品类满意度占比getOneCategoryRankChart查询结束");
            transToOneRankArray(commentRateVO, categoryRateArray);
            resultMap.put("categoryRateChart", categoryRateArray);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("品类满意度占比getOneCategoryRankChart查询出错:" + e.getMessage(), e);
        }
        return resultMap;
    }

    private void transToOneRankArray(CategoryCommentRateVO commentRateVO, JSONArray categoryRateArray) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", "好评");
        jsonObject.put("value", commentRateVO.getFavorRate());
        categoryRateArray.add(jsonObject);

        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("name", "中评");
        jsonObject1.put("value", commentRateVO.getMiddleRate());
        categoryRateArray.add(jsonObject1);

        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("name", "差评");
        jsonObject2.put("value", commentRateVO.getWorstRate());
        categoryRateArray.add(jsonObject2);
    }

    private void transTorankArray(JSONArray commentRateArray, List<CategoryCommentCountVO> rankChartVoList,
                                  Map<String, Object> resultMap) {

        List<String> categoryNamesList = new ArrayList<>();
        List<Float> favorRateList = new ArrayList<>();
        List<Float> middleRateList = new ArrayList<>();
        List<Float> worstRateList = new ArrayList<>();

        if (!CollectionUtils.isEmpty(rankChartVoList)) {


            for (int i = 0; i < rankChartVoList.size(); i++) {
                CategoryCommentCountVO vo = rankChartVoList.get(i);

                String categoryShowName = EnumForCategory.getCategoryShowName(vo.getCategoryId());
                if (StringUtils.isBlank(categoryShowName)) {
                    rankChartVoList.remove(i);
                    i--;
                    continue;
                }
                categoryNamesList.add(categoryShowName);
                favorRateList.add(vo.getFavorCount());
                middleRateList.add(vo.getMiddleCount());
                worstRateList.add(vo.getWorstCount());
            }

            Object[] favorRate = favorRateList.toArray();
            Object[] middleRate = middleRateList.toArray();
            Object[] worstRate = worstRateList.toArray();

            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("name", "好评量");
            jsonObject1.put("data", favorRate);
            commentRateArray.add(jsonObject1);

            JSONObject jsonObject2 = new JSONObject();
            jsonObject2.put("name", "中评量");
            jsonObject2.put("data", middleRate);
            commentRateArray.add(jsonObject2);

            JSONObject jsonObject3 = new JSONObject();
            jsonObject3.put("name", "差评量");
            jsonObject3.put("data", worstRate);
            commentRateArray.add(jsonObject3);
        }

        Object[] categoryNames = categoryNamesList.toArray();
        resultMap.put("categoryName", categoryNames);
        resultMap.put("commentRateChart", commentRateArray);
    }

    @RequestMapping("categoryRank")
    public String categoryRankView(ModelMap model, String flag, String choose_date, String categoryId,
                                   String sentiment, String tags, String categoryName, String isocategory,
                                   String timeLabel, String overviewDay, String ocategoryName,
                                   String ocategoryId, String isbackbtn) {

        model.put("flag", flag);
        model.put("catetime", choose_date);

        // 产品返回
        model.put("pcategoryId", categoryId);
        model.put("psentiment", sentiment);
        model.put("ptags", tags);
        model.put("pcategoryName", categoryName);
        model.put("timeLabel", timeLabel);

        // 点评概览
        model.put("overviewDay", overviewDay);
        model.put("choose_date", choose_date);

        model.put("ocategoryName", ocategoryName);
        if (!StringUtils.isEmpty(ocategoryId)) {
            model.put("ocategoryId", ocategoryId);
        } else {
            model.put("ocategoryId", EnumForCategory.getCategoryValueByShowName(ocategoryName));
        }
        model.put("isocategory", isocategory);
        model.put("isbackbtn", isbackbtn);
        return "application/category/categoryRank";
    }

    /**
     * 各品类评价详情
     * @param request
     * @return
     */
    @RequestMapping(value = "getCategoryRank", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getCategoryRank(CategoryRankRequest request) {
        List<CategoryRankVO> categoryRankList = new ArrayList<>();
        Map<String, Object> resultMap = new HashMap<>();
        WorstRateCategoryVO vo = new WorstRateCategoryVO();
        String categoryRankListStr;
        try {
            if (StringUtils.isEmpty(request.getOverviewDay())) {
                Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
                request.setBeginDate(map.get("beginDate"));
                request.setEndDate(map.get("endDate"));
            }

            String key = redisService.getKey("getCategoryRank");
            if(isCategoryRankQueryRedis(request.getBeginDate(), request.getEndDate(), request.getOverviewDay())
                    && StringUtils.isBlank(request.getOverviewDay())) {
                log.info("category getCategoryRank redis query start");
                categoryRankListStr = redisService.getObjectValue(key);
                log.info("category getCategoryRank redis query end");
                if (StringUtils.isNotBlank(categoryRankListStr)) {
                    categoryRankList = new Gson().fromJson(categoryRankListStr, new TypeToken<List<CategoryRankVO>>() {}.getType());
                } else {
                    categoryRankList = queryCategoryRank(request);
                    redisService.setValueExpire(key, categoryRankList, Constants.TIMEOUT);
                }
            } else {
                categoryRankList = queryCategoryRank(request);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("category getCategoryRank query error:" + e.getMessage(), e);
            try {
                categoryRankList = queryCategoryRank(request);
            } catch (Exception e1) {
                e1.printStackTrace();
                log.error("category getCategoryRank mysql requery error:" + e.getMessage(), e);
            }
        }

        try {
            // 枚举转换并检查检查好中差评计算准确性
            transCategoryEnum(categoryRankList);
            // 获取差评率最高的品类
            vo = getWorstRateCategory(categoryRankList);
            log.info("差评率最高的品类是" + vo.getCategoryName());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("category getCategoryRank analysis error:" + e.getMessage(), e);
        }

        resultMap.put("categoryRank", categoryRankList);
        resultMap.put("worstRateCategory", vo);
        return resultMap;
    }

    /**
     * 各品类评价详情-mysql
     * @param request
     * @return
     */
    private List<CategoryRankVO> queryCategoryRank(CategoryRankRequest request) {
        log.info("category getCategoryRank mysql query start");
        List<CategoryRankVO> categoryRankVOList = categoryRankService.getCategoryRank(request);
        log.info("category getCategoryRank mysql query end");
        return  categoryRankVOList;
    }

    /**
     * 品类评价排名
     * 7天内的数据查询redis
     *
     * @param begin
     * @param end
     * @return
     */
    private boolean isCategoryRankQueryRedis(Date begin, Date end, String overviewDay) throws Exception {

        String dataFormat = "yyyyMMdd";
        SimpleDateFormat sdf = new SimpleDateFormat(dataFormat);
        String startTime = sdf.format(DateUtil.getDateBeforeWeek(new Date()));
        String endTime = DateUtil.getStrDate(-1, new Date(), dataFormat);
        if (null == begin && null == end && String.valueOf(CommentDaysEnum.WEEK.getCode()).equals(overviewDay)) {
            return true;
        } else if (null != begin && null != end && startTime.equals(sdf.format(begin)) && endTime.equals(sdf.format(end))) {
            return true;
        }
        return false;
    }

    /**
     * 第一次加载页面,查询差评率最高的品类
     * @param categoryRankList
     * @return
     */
    private WorstRateCategoryVO getWorstRateCategory(List<CategoryRankVO> categoryRankList) {
        WorstRateCategoryVO vo = new WorstRateCategoryVO();
        if (!CollectionUtils.isEmpty(categoryRankList) && StringUtils.isNotBlank(categoryRankList.get(0).getCategoryId())) {
            CategoryRankVO categoryRankVO = categoryRankList.get(0);
            vo.setWorstRate(String.valueOf(categoryRankVO.getWorstRate()));
            vo.setCategoryId(categoryRankVO.getCategoryId());
            vo.setCategoryName(categoryRankVO.getCategoryName());
        }

        vo.setSentiment(String.valueOf(EnumForComment.negative.getValue()));
        return vo;
    }

    @RequestMapping(value = "getCategoryRankChart", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getCategoryRankChart(CategoryRankChartRequest request) {
        Map<String, Object> resultMap = new HashMap<>();
        JSONArray rankChartArray = new JSONArray();
        try {
            String overviewDay = request.getOverviewDay();
            String chooseTime = request.getChooseTime();
            if (CommentDaysEnum.YEAR.getCode().toString().equals(overviewDay)) {
                request.setOverviewDay(null);
            } else if (!CommentDaysEnum.HALF_A_MONTH.getCode().toString().equals(overviewDay)
                    && !StringUtils.isEmpty(chooseTime)) {
                request.setOverviewDay(null);
                Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
                request.setBeginDate(map.get("beginDate"));
                request.setEndDate(map.get("endDate"));
            }
            List<CategoryRankChartVO> rankChartVoList = categoryRankService.getCategoryRankChart(request);
            // 转换格式为json数组
            transToJsonarray(rankChartVoList, rankChartArray);
            resultMap.put("rankChart", rankChartArray);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultMap;
    }

    @RequestMapping(value = "getCategoryProductRank", method = RequestMethod.POST)
    @ResponseBody
    public PageInfo<CategoryProductRankVO> getCategoryProductRank(CategoryProductRankRequest request) {
        PageInfo<CategoryProductRankVO> categoryProductRankList = null;
        try {
            if (StringUtils.isEmpty(request.getOverviewDay())) {
                Map<String, Date> map = DateUtil.getSelectDate(request.getChooseTime());
                request.setBeginDate(map.get("beginDate"));
                request.setEndDate(map.get("endDate"));
            }
            categoryProductRankList = categoryRankService.getCategoryProductRank(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return categoryProductRankList;
    }

    /**
     * 转换格式为json数组
     *
     * @param rankChartVoList
     * @param rankChartArray
     */

    private void transToJsonarray(List<CategoryRankChartVO> rankChartVoList, JSONArray rankChartArray) {
        if (!CollectionUtils.isEmpty(rankChartVoList)) {
            for (int i = 0; i < rankChartVoList.size(); i++) {
                CategoryRankChartVO vo = rankChartVoList.get(i);
                JSONObject orderAmountOb = new JSONObject();
                orderAmountOb.put("num", vo.getNum());
                orderAmountOb.put("tags", vo.getTags());
                rankChartArray.add(orderAmountOb);
            }
        }
    }

    /**
     * 枚举转换
     *
     * @param categoryRankList
     */
    private void transCategoryEnum(List<CategoryRankVO> categoryRankList) throws Exception {

        if (!CollectionUtils.isEmpty(categoryRankList)) {
            for (int i = 0; i < categoryRankList.size(); i++) {
                CategoryRankVO categoryRankVO = categoryRankList.get(i);
                // 品类名称
                String categoryId = categoryRankVO.getCategoryId();
                String categoryName = !StringUtils.isEmpty(categoryId) ?
                        EnumForCategory.getCategoryShowName(categoryId) : null;
                if (StringUtils.isBlank(categoryName)) {
                    categoryRankList.remove(i);
                    i--;
                    continue;
                }
                categoryRankVO.setCategoryName(categoryName);

                // 检查好中差评计算准确性
                float good = StringTools.checkCategoryCommentRate(categoryRankVO.getFavorRate(),
                        categoryRankVO.getWorstRate(), categoryRankVO.getMiddleRate());
                categoryRankVO.setFavorRate(good);
            }
        }
    }

}
